package lightswitch.server.code.object;

import java.util.List;
import java.util.Vector;

import lightswitch.server.code.sqlhelper.expression.NormalTable;

public class Database {
    public boolean flagChangeData;
    public static String lastChosenTable;
    public static Vector<Table> tables;
    public String name;
    public Database(Vector<Table> tablesValue) {
        tables = tablesValue;
        flagChangeData = false;
        lastChosenTable = null;
        name = null;
    }

    public static Table getLoadedTable(String name) {
        for (Table tb : tables) {
            if (tb.getName().equals(name)) {
                return tb;
            }
        }
        return null;
    }

    public Vector<String> getListOfLoadedNameTables() {
        Vector<String> result = new Vector<String>();
        for (Table tb : tables) {
            result.add(tb.getName());
        }

        return result;
    }

    public String getName() {
        return name;
    }

    public int getSizeTables() {
        if (tables != null)
            return tables.size();
        return 0;
    }

    public Table getTable(int index) {
        return tables.get(index);
    }

    public boolean addTable(Table table) {
        return tables.add(table);
    }

    public Table removeTable(int index) {
        return tables.remove(index);
    }

    public void addNewPropertyToLastTable(Property p) {
        getLoadedTable(lastChosenTable).addProperty(p);
    }

    public Object[] getListNameOfTablesExceptCurrent() {
        Vector<Object> result = new Vector<Object>();
        for (int i = 0; i < tables.size(); i++) {
            if (!tables.get(i).getName().equals(lastChosenTable)) {
                result.add(tables.get(i).getName());
            }
        }
        return result.toArray();
    }

    public void addNewRefToLastTable(Reference r) {
        getLoadedTable(lastChosenTable).addReference(r);
    }

    public boolean isExistNameOfReferenceInTable(String refName, String nameTableRefTo) {
        Table tb = getLoadedTable(nameTableRefTo);
        if (tb != null) {
            if (tb.getSizeReferences() == 0)
                return false;
            for (String name : tb.getAllRefsName()) {
                if (name.equals(refName)) {
                    return true;
                }
            }
        }
        return false;
    }

    public static Vector<String> getAllValueOfFieldInSpecifiedTable(String tableName, String propertyName) {
        Vector<String> result = new Vector<String>();
        Table tb = getLoadedTable(tableName);
        for (int i = 0; i < tb.getSizeDataRows(); i++) {
            DataRow dr = tb.getDataRow(i);
            for (int j = 0; j < dr.getSize(); j++) {
                if (dr.getEntry(j).getName().equals(propertyName)) {
                    result.add(dr.getEntry(j).getValue());
                }
            }
        }
        return result;
    }

    public String getAllRefsString(String tableName) {
        String result = "";
        Table tb = getLoadedTable(tableName);
        for (int i = 0; i < tb.getSizeReferences(); i++) {
            String nex = tb.getReference(i).getString();
            result += nex + "\n";
        }
        return result;
    }

    public Object[] getAllRefencesNameInSpecifiedTable(String tableName) {
        Vector<String> result = new Vector<String>();
        Table tb = Database.getLoadedTable(tableName);
        result = tb.getAllRefsName();
        return result.toArray();
    }

    public static boolean addNewDataRow(String tableName, DataRow dr) {
        // XXX
        Table tb = Database.getLoadedTable(tableName);
        return tb.addDataRow(dr, true);
    }

    public void changeDataroẉ̣̣̣̣̣(Object value, int row, int col) {

    }

    public static int editTable(NormalTable mainTable) {
        int rowEff = 0;
        Table tb = getLoadedTable(mainTable.name);
        List<DataRow> main = mainTable.dataRowList;

        List<DataRow> drs = tb.getListOfDataRows();

        if (main.size() == 0) {
            for (int i = 0; i < drs.size(); i++) {
                if (Database.isCanRemove(mainTable.name, drs.get(i))) {
                    drs.remove(drs.get(i));
                    rowEff++;
                }
                i--;

            }
            return rowEff;
        }

        for (int i = drs.size() - 1; i >= 0; i--) {

            boolean found = false;
            for (int j = 0; j < main.size(); j++) {

                if (main.get(j).getChainOfValues().equals(drs.get(i).getChainOfValues())) {
                    found = true;
                }
            }
            if (found == false) {
                if (Database.isCanRemove(mainTable.name, drs.get(i))) {
                    drs.remove(drs.get(i));
                    i--;
                    rowEff++;
                }
            }

        }
        return rowEff;
    }

    public static int updateTable(NormalTable mainTable) {
        int rowEff = 0;
        Table tb = getLoadedTable(mainTable.name);
        List<DataRow> main = mainTable.dataRowList;
        List<DataRow> drs = tb.getListOfDataRows();

        if (main.size() == 0)
            return rowEff;

        for (int i = drs.size() - 1; i > 0; i--) {

            boolean found = false;
            for (int j = 0; j < main.size(); j++) {

                if (main.get(j).getChainOfValues().equals(drs.get(i).getChainOfValues())) {
                    found = true;
                    break;
                }
            }
            if (found == false) {
                int index = drs.indexOf(drs.get(i));
                if (Database.isCanUpdate(mainTable.name, drs.get(i), main.get(i))) {
                    drs.set(index, main.get(i));
                    rowEff++;
                }
            }

        }
        return rowEff;
    }

    public static boolean isCanUpdate(String tableName, DataRow oldDataRow, DataRow newDataRow) {
        if (oldDataRow.getChainOfValues().equals(newDataRow.getChainOfValues())) {
            return false;
        }

        Table tb = getLoadedTable(tableName);
        // check primary key
        String oldPri = tb.getChainOfPrimaryKeyValue(oldDataRow);
        String newPri = tb.getChainOfPrimaryKeyValue(newDataRow);
        if (oldPri != null && !"".equals(oldDataRow)) {
            for (int i = 0; i < tb.getSizeDataRows(); i++) {
                String curPri = tb.getChainOfPrimaryKeyValue(i);
                if (curPri == null || "".equals(curPri))
                    break;
                if (!oldPri.equals(newPri) && curPri.equals(newPri)) {
                    return false;
                }
            }
        }
        // check any reference ref to me
        List<Reference> refToMe = getRefToMe(tableName);
        for (Reference r : refToMe) {
            if (!oldDataRow.getValue(r.getFieldRef()).equals(newDataRow.getValue(r.getFieldRef()))) {
                Table tbRefToMe = getLoadedTable(r.getTableRef());
                for (DataRow dr : tbRefToMe.getListOfDataRows()) {
                    if (dr.getValue(r.getField()).equals(oldDataRow.getValue(r.getFieldRef()))) {
                        return false;
                    }
                }
            }
        }

        // check value of me ref to another table use listOfReference
        if (!tb.isValidValueWithReference(newDataRow)) {
            return false;
        }

        //Check datatype & range
        for (int i=0; i<newDataRow.getSize(); i++){
            MyEntry entry = newDataRow.getEntry(i);
            Property p = tb.getProperty(entry.getOriginName());
            if (!newDataRow.getEntry(i).checkEntry(p.getMaxTypeLength())){
                return false;
            }
        }
        
        return true;
    }

    public static boolean isCanRemove(String tableName, DataRow dataRow) {
        for (Table tb : tables) {
            if (tb.getSizeReferences() > 0) {
                for (Reference r : tb.getListOfReferences()) {
                    if (r.getTableRef().equals(tableName)) {
                        String fieldName = r.getField();
                        MyEntry entryIsRefed = dataRow.getEntry(fieldName);
                        if (entryIsRefed == null)
                            break;
                        if (tb.isHaveEntry(entryIsRefed))
                            return false;
                    }
                }
            }
        }
        return true;
    }

    public static Vector<Reference> getRefToMe(String tableName) {
        Vector<Reference> result = new Vector<Reference>();
        for (Table tb : tables) {
            if (tb.getSizeReferences() > 0) {
                for (Reference r : tb.getListOfReferences()) {
                    if (r.getTableRef().equals(tableName)) {
                        result.add(r);
                    }
                }
            }
        }
        return result;
    }

    public static boolean checkEditDataDirectInCell(Vector<Object> rowVector, int col, Object value) {
        Table tb = getLoadedTable(Database.lastChosenTable);
        List<DataRow> drs = tb.getListOfDataRows();
        for (DataRow dr : drs){
            if (dr.getChainOfValues().equals(rowVector)){
                DataRow newRow = new DataRow(dr);
                newRow.setEntry(col, value);
                if (isCanUpdate(lastChosenTable, dr, newRow))
                    return true;
                return false;
            }
        }
        
        return false;
    }

    public Vector<String> getListOfLoadedNameTablesHaveProperty() {
        Vector<String> result = new Vector<String>();
        for (Table tb : tables) {
            if(tb.getSizeProperties()>0)
                result.add(tb.getName());
        }

        return result;
    }

}
